package com.whmskj.xjlhsc.service.impl;

import com.whmskj.xjlhsc.mapper.EnergyKbMapper;
import com.whmskj.xjlhsc.service.EnergyKbService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 能耗看板服务实现类
 *
 * @author lk
 * @since 2025-08-14
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class EnergyKbServiceImpl implements EnergyKbService {

    @Autowired
    private EnergyKbMapper energyConsumptionMapper;

    @Override
    public List<Map<String, Object>> getLast7DaysShiftEnergy() {
        // 区间：今天往前推6天到明天（end 为开区间）
        LocalDate today = LocalDate.now();
        LocalDate startDate = today.minusDays(6);
        LocalDate endDate = today.plusDays(1);

        List<Map<String, Object>> dbList = energyConsumptionMapper.selectShiftEnergyBetween(
                startDate.atStartOfDay(), endDate.atStartOfDay());

        // 以日期为键，补全缺失日期并置0
        Map<String, Map<String, Object>> byDay = dbList.stream()
                .collect(Collectors.toMap(m -> String.valueOf(m.get("day")), m -> m));

        List<Map<String, Object>> result = new ArrayList<>();
        for (int i = 0; i < 7; i++) {
            LocalDate d = startDate.plusDays(i);
            String key = d.toString();
            Map<String, Object> row = byDay.get(key);
            if (row == null) {
                Map<String, Object> empty = new HashMap<>();
                empty.put("day", key);
                empty.put("morningEnergy", scale2(java.math.BigDecimal.ZERO));
                empty.put("nightEnergy", scale2(java.math.BigDecimal.ZERO));
                result.add(empty);
            } else {
                // 确保字段存在
                row.put("morningEnergy", scale2(row.get("morningEnergy")));
                row.put("nightEnergy", scale2(row.get("nightEnergy")));
                result.add(row);
            }
        }
        return result;
    }
    
    public Map<String, Object> getProcessEnergyByPeriod(String period, LocalDate day) {
        LocalDate base = (day == null ? LocalDate.now() : day);
        LocalDate start;
        LocalDate end;
        switch (period == null ? "day" : period.toLowerCase()) {
            case "week":
                start = base.with(java.time.DayOfWeek.MONDAY);
                end = base.plusDays(1);
                break;
            case "month":
                if (base.getDayOfMonth() >= 20) {
                    start = base.withDayOfMonth(20);
                    java.time.LocalDate next = base.plusMonths(1);
                    // 盘存月结束（含）为下月21日，转开区间需 +1 天
                    end = next.withDayOfMonth(21).plusDays(1);
                } else {
                    java.time.LocalDate prev = base.minusMonths(1);
                    start = prev.withDayOfMonth(20);
                    end = base.withDayOfMonth(21).plusDays(1);
                }
                break;
            default:
                start = base;
                end = base.plusDays(1);
        }

        List<Map<String, Object>> rows = energyConsumptionMapper.selectProcessEnergyBetween(
                start.atStartOfDay(), end.atStartOfDay());

        java.math.BigDecimal total = rows.stream()
                .map(r -> toBD(r.get("energy")))
                .reduce(java.math.BigDecimal.ZERO, java.math.BigDecimal::add);

        for (Map<String, Object> r : rows) {
            java.math.BigDecimal en = toBD(r.get("energy"));
            r.put("energy", en.setScale(2, java.math.RoundingMode.HALF_UP));
            java.math.BigDecimal ratio = total.compareTo(java.math.BigDecimal.ZERO) == 0
                    ? java.math.BigDecimal.ZERO
                    : en.multiply(new java.math.BigDecimal("100"))
                        .divide(total, 2, java.math.RoundingMode.HALF_UP);
            r.put("ratio", ratio);
        }

        Map<String, Object> result = new HashMap<>();
        result.put("total", total.setScale(2, java.math.RoundingMode.HALF_UP));
        result.put("items", rows);
        return result;
    }

    private java.math.BigDecimal toBD(Object v) {
        if (v == null) return java.math.BigDecimal.ZERO;
        if (v instanceof java.math.BigDecimal) return (java.math.BigDecimal) v;
        if (v instanceof Number) return java.math.BigDecimal.valueOf(((Number) v).doubleValue());
        try { return new java.math.BigDecimal(String.valueOf(v)); } catch (Exception e) { return java.math.BigDecimal.ZERO; }
    }

    @Override
    public List<Map<String, Object>> getProcessEnergyOverview(LocalDate day) {
        LocalDate base = (day == null ? LocalDate.now() : day);

        // 昨日
        Map<String, Object> y = getProcessEnergyByPeriod("day", base.minusDays(1));
        Map<String, java.math.BigDecimal> yMap = toProcessMap(y);

        // 本周（周一~当天）
        Map<String, Object> w = getProcessEnergyByPeriod("week", base);
        Map<String, java.math.BigDecimal> wMap = toProcessMap(w);

        // 本月（盘存月）
        Map<String, Object> m = getProcessEnergyByPeriod("month", base);
        Map<String, java.math.BigDecimal> mMap = toProcessMap(m);

        // 本年（自然年1-1到当天）
        LocalDate yStart = base.withDayOfYear(1);
        List<Map<String, Object>> yearRows = energyConsumptionMapper.selectProcessEnergyBetween(
                yStart.atStartOfDay(), base.plusDays(1).atStartOfDay());
        Map<String, java.math.BigDecimal> yxMap = new java.util.HashMap<>();
        for (Map<String, Object> r : yearRows) {
            yxMap.put(String.valueOf(r.get("process")), toBD(r.get("energy")));
        }

        // 合并所有工序键
        java.util.Set<String> processes = new java.util.TreeSet<>();
        processes.addAll(yMap.keySet());
        processes.addAll(wMap.keySet());
        processes.addAll(mMap.keySet());
        processes.addAll(yxMap.keySet());

        List<Map<String, Object>> list = new ArrayList<>();
        for (String p : processes) {
            Map<String, Object> row = new HashMap<>();
            row.put("process", p);
            row.put("yesterday", yMap.getOrDefault(p, java.math.BigDecimal.ZERO).setScale(2, java.math.RoundingMode.HALF_UP));
            row.put("thisWeek", wMap.getOrDefault(p, java.math.BigDecimal.ZERO).setScale(2, java.math.RoundingMode.HALF_UP));
            row.put("thisMonth", mMap.getOrDefault(p, java.math.BigDecimal.ZERO).setScale(2, java.math.RoundingMode.HALF_UP));
            row.put("thisYear", yxMap.getOrDefault(p, java.math.BigDecimal.ZERO).setScale(2, java.math.RoundingMode.HALF_UP));
            list.add(row);
        }
        return list;
    }

    private Map<String, java.math.BigDecimal> toProcessMap(Map<String, Object> result) {
        Map<String, java.math.BigDecimal> map = new java.util.HashMap<>();
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> items = (List<Map<String, Object>>) result.get("items");
        if (items != null) {
            for (Map<String, Object> r : items) {
                map.put(String.valueOf(r.get("process")), toBD(r.get("energy")));
            }
        }
        return map;
    }

    public Map<String, Object> getWorkshopTrend(String period, LocalDate day) {
        LocalDate base = (day == null ? LocalDate.now() : day);
        LocalDate start;
        LocalDate end;
        int points;
        String p = period == null ? "day" : period.toLowerCase();
        switch (p) {
            case "week":
                LocalDate monday = base.with(java.time.DayOfWeek.MONDAY);
                start = monday.minusWeeks(6);
                end = monday.plusWeeks(1); // 下周一零点
                points = 7;
                break;
            case "month":
                // 近7个盘存月：如果 base>=当月20日，则当前盘存月起点=本月20日；否则=上月20日
                LocalDate invStartCurrent;
                if (base.getDayOfMonth() >= 20) {
                    invStartCurrent = base.withDayOfMonth(20);
                } else {
                    invStartCurrent = base.minusMonths(1).withDayOfMonth(20);
                }
                start = invStartCurrent.minusMonths(6); // 从6个盘存月前的起点
                // 结束为当前盘存月的结束次日：当前起点+1个月的21日再+1天
                LocalDate invEndCurrent = invStartCurrent.plusMonths(1).withDayOfMonth(21).plusDays(1);
                end = invEndCurrent;
                points = 7;
                break;
            default:
                start = base.minusDays(6);
                end = base.plusDays(1);
                points = 7;
        }

        List<Map<String, Object>> rows;
        if ("week".equals(p)) {
            rows = energyConsumptionMapper.selectWorkshopEnergyWeeklyBetween(start.atStartOfDay(), end.atStartOfDay());
        } else if ("month".equals(p)) {
            rows = energyConsumptionMapper.selectWorkshopEnergyInventoryMonthlyBetween(start.atStartOfDay(), end.atStartOfDay());
        } else {
            rows = energyConsumptionMapper.selectWorkshopEnergyDailyBetween(start.atStartOfDay(), end.atStartOfDay());
        }

        // 车间集合
        java.util.Set<String> workshops = new java.util.TreeSet<>();
        for (Map<String, Object> r : rows) {
            Object w = r.get("workshop");
            if (w != null) workshops.add(String.valueOf(w));
        }

        // 横轴
        List<String> axis = new ArrayList<>();
        if ("week".equals(p)) {
            LocalDate cur = start;
            for (int i = 0; i < points; i++) { axis.add(cur.toString()); cur = cur.plusWeeks(1); }
        } else if ("month".equals(p)) {
            LocalDate cur = start;
            for (int i = 0; i < points; i++) { axis.add(cur.toString().substring(0,7)); cur = cur.plusMonths(1); }
        } else {
            for (int i = 0; i < points; i++) { axis.add(start.plusDays(i).toString()); }
        }

        // 准备 series 容器
        Map<String, Map<String, Object>> series = new LinkedHashMap<>();
        for (String w : workshops) {
            Map<String, Object> s = new LinkedHashMap<>();
            s.put("name", w);
            List<java.math.BigDecimal> data = new ArrayList<>();
            for (int i = 0; i < points; i++) data.add(java.math.BigDecimal.ZERO);
            s.put("data", data);
            series.put(w, s);
        }

        Map<String, Integer> idxMap = new HashMap<>();
        for (int i = 0; i < axis.size(); i++) idxMap.put(axis.get(i), i);

        for (Map<String, Object> r : rows) {
            String key = "week".equals(p) || "month".equals(p)
                    ? String.valueOf(r.get("periodKey"))
                    : String.valueOf(r.get("day"));
            String w = String.valueOf(r.get("workshop"));
            java.math.BigDecimal en = toBD(r.get("energy")).setScale(2, java.math.RoundingMode.HALF_UP);
            Integer idx = idxMap.get(key);
            Map<String, Object> s = series.get(w);
            if (idx != null && s != null) {
                @SuppressWarnings("unchecked")
                List<java.math.BigDecimal> data = (List<java.math.BigDecimal>) s.get("data");
                data.set(idx, en);
            }
        }

        Map<String, Object> result = new HashMap<>();
        result.put("dates", axis);
        result.put("series", new ArrayList<>(series.values()));
        return result;
    }

    private java.math.BigDecimal scale2(Object value) {
        java.math.BigDecimal bd;
        if (value == null) {
            bd = java.math.BigDecimal.ZERO;
        } else if (value instanceof java.math.BigDecimal) {
            bd = (java.math.BigDecimal) value;
        } else if (value instanceof Number) {
            bd = java.math.BigDecimal.valueOf(((Number) value).doubleValue());
        } else {
            try {
                bd = new java.math.BigDecimal(String.valueOf(value));
            } catch (Exception e) {
                bd = java.math.BigDecimal.ZERO;
            }
        }
        return bd.setScale(2, java.math.RoundingMode.HALF_UP);
    }
}
